package com.ghh.app.monsterrush;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.utils.TimeUtils;
import com.ghh.app.monsterrush.monsters.MonsterFactory;
import com.ghh.app.monsterrush.weapons.WeaponFactory;

public class MonsterRushGameScreen implements Screen, MonsterRushGame {
	private final int			screenWidth				= 480;
	private final int			screenHeight			= 854;
	private final int			columns					= 4;
	private final float			columnWidth				= screenWidth / columns;

	private WeaponFactory		weaponFactory			= new WeaponFactory(this);
	private MonsterFactory		monsterFactory			= new MonsterFactory(this);

	private OrthographicCamera	camera;
	private Stage				stage;
	private Music				backgroundMusic;
	private Texture				tx_background;
	private Random				random					= new Random();
	private float				wpCenterX				= screenWidth / 2;					// weapon centerX
	private float				wpCenterY				= 200;								// weapon centerX

	private List<MonsterActor>	monsters				= new ArrayList<MonsterActor>();
	private List<WeaponActor>	weapons					= new ArrayList<WeaponActor>();
	private Group				monsterGroup			= new Group();
	private Group				weaponGroup				= new Group();
	private WeaponActor			currentWeapon;												// current standby weapon

	private long				lastMonsterCreateTime	= 0;
	private long				monsterInterval			= 2000;
	private SpriteBatch			spriteBatch				= new SpriteBatch();
	private Sprite				bgSprite;

	public MonsterRushGameScreen() {
		backgroundMusic = Gdx.audio.newMusic(Gdx.files.internal("bgsound.mp3"));
		backgroundMusic.setLooping(true);

		Texture.setEnforcePotImages(false);
		tx_background = new Texture(Gdx.files.internal("background.jpg"));
		tx_background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
		bgSprite = new Sprite(tx_background, screenWidth, screenHeight);

		stage = new Stage(screenWidth, screenHeight, true);
		Gdx.input.setInputProcessor(stage);

		stage.addActor(monsterGroup);
		stage.addActor(weaponGroup);
	}

	@Override
	public void show() {
		backgroundMusic.play();
		camera = new OrthographicCamera();
		camera.setToOrtho(false, screenWidth, screenHeight);

		stage.getSpriteBatch().setProjectionMatrix(camera.combined);
		spriteBatch.setProjectionMatrix(camera.combined);

		currentWeapon = createWeapon();
	}

	private void drawBackground() {
		spriteBatch.begin();
		bgSprite.draw(spriteBatch);
		spriteBatch.end();
	}

	@Override
	public void render(float arg0) {
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
		Gdx.gl.glClearColor(1f, 1f, 1f, 0f);
		camera.update();

		drawBackground();

		stage.act(Gdx.graphics.getDeltaTime());
		stage.draw();

		recycleActors();
		if (lastMonsterCreateTime == 0 || (TimeUtils.millis() - lastMonsterCreateTime) >= monsterInterval) {
			spawnMonster();
		}
	}

	@Override
	public boolean isBlocked(MonsterActor monster) {
		for (MonsterActor m : monsters) {
			if (monster == m) {
				break;
			}
			if (isOverlaps(monster, m)) {
				if (m.getZIndex() <= monster.getZIndex()) {
					m.setZIndex(monster.getZIndex() + 1);
				}
			}
			if (isBlocked(monster, m)) {
				return true;
			}
		}
		return false;
	}

	private boolean isOverlaps(MonsterActor back, MonsterActor front) {
		Rectangle r1 = new Rectangle(back.getX(), back.getY(), back.getWidth(), back.getHeight());
		Rectangle r2 = new Rectangle(front.getX(), front.getY(), front.getWidth(), front.getHeight());
		return r1.overlaps(r2);
	}

	private boolean isBlocked(MonsterActor back, MonsterActor front) {
		Rectangle r1 = new Rectangle(back.getX(), back.getY(), back.getWidth(), back.getHeight());
		Rectangle r2 = new Rectangle(front.getX(), front.getY(), front.getWidth(), (front.getHeight() * 2) / 3);
		return r1.overlaps(r2);
	}

	@Override
	public void onWeaponReady() {
		weapons.add(currentWeapon);
		currentWeapon = createWeapon();
	}

	private void recycleActors() {
		Iterator<MonsterActor> itm = monsters.iterator();
		while (itm.hasNext()) {
			MonsterActor monster = itm.next();
			if (monster.isDestroyed()) {
				remove(monster);
				itm.remove();
			}
		}

		Iterator<WeaponActor> itw = weapons.iterator();
		while (itw.hasNext()) {
			WeaponActor weapon = itw.next();
			if (weapon.isDestroyed()) {
				remove(weapon);
				itw.remove();
			}
		}
	}

	@Override
	public void onUpdateWeapon(WeaponActor weapon) {
		Rectangle bound = weapon.getBound();
		if (bound.getX() >= stage.getWidth() 
				|| bound.getX() <= 0 - bound.getWidth() 
				|| bound.getY() >= stage.getHeight() - bound.getHeight()
				|| bound.getY() <= 0 - bound.getHeight()) {
			weapon.destroy();
			return;
		}

		Iterator<MonsterActor> itr = monsters.iterator();
		while (itr.hasNext()) {
			MonsterActor monster = itr.next();
			if (monster.isDead()) {
				continue;
			}
			if (weapon.isAttacking() && hitMonster(weapon, monster)) {
				monster.onAttacked(weapon);
				weapon.onAttack();
				break;
			}
		}
	}

	private void remove(WeaponActor weapon) {
		weaponGroup.removeActor(weapon);
		weapon.dispose();
	}

	private void remove(MonsterActor monster) {
		monsterGroup.removeActor(monster);
		monster.dispose();
	}

	private void spawnMonster() {
		MonsterActor monster = monsterFactory.create();
		monster.setZIndex(0);

		int x = random.nextInt(columns);
		float posx = columnWidth * x + (columnWidth - monster.getWidth()) / 2;
		monster.setPosition(posx, monster.getHeight() + screenHeight);

		monsters.add(monster);
		monsterGroup.addActor(monster);

		lastMonsterCreateTime = TimeUtils.millis();
	}

	private WeaponActor createWeapon() {
		WeaponActor weapon = weaponFactory.create();
		weapon.setPosition(wpCenterX - (weapon.getWidth() / 2), wpCenterY - weapon.getHeight());
		weaponGroup.addActor(weapon);
		return weapon;
	}

	private boolean hitMonster(WeaponActor wp, MonsterActor ms) {
		Rectangle rwp = wp.getBound();
		Rectangle rms = new Rectangle(ms.getX(), ms.getY(), ms.getWidth(), ms.getHeight());
		return rwp.overlaps(rms);
	}

	@Override
	public void dispose() {
		tx_background.dispose();
		spriteBatch.dispose();

		if (currentWeapon != null) {
			currentWeapon.dispose();
		}

		Iterator<MonsterActor> itm = monsters.iterator();
		while (itm.hasNext()) {
			MonsterActor monster = itm.next();
			monster.onDestroying();
			itm.remove();
		}

		Iterator<WeaponActor> itw = weapons.iterator();
		while (itw.hasNext()) {
			WeaponActor weapon = itw.next();
			weapon.destroy();
			itm.remove();
		}

		stage.dispose();
	}

	@Override
	public void hide() {
	}

	@Override
	public void pause() {
	}

	@Override
	public void resize(int arg0, int arg1) {
	}

	@Override
	public void resume() {
	}
}
